package com.yihaodian.server.servlet.rest;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.yihaodian.api.client.BrokerService;
import com.yihaodian.api.client.JsonConvertor;
import com.yihaodian.api.index.IndexRequest;
import com.yihaodian.cluster.ClusterService;
import com.yihaodian.cluster.ClusterState;
import com.yihaodian.index.solr.ext.MemDataManager;
import com.yihaodian.indices.IndicesService;

/**
 * Index related operations.
 * 
 * List EMF Fields: /search/reset/index/<indexName>/emfs -
 * http://192.168.18.31:8180/search/rest/index/product/emfs
 * 
 * Dump EMF Values: /search/reset/index/<indexName>/emf/<fieldName> -
 * http://192.168.18.31:8180/search/rest/index/product/emf/merchantFactor
 * 
 * Dump EMF Value: /search/reset/index/<indexName>/emf/<fieldName>/<key> -
 * http:/
 * /192.168.18.31:8180/search/rest/index/product/emf/merchantFactor/merchant1
 * 
 * Update EMF Value:
 * /search/reset/index/<indexName>/emf/<fieldName>/<key>?val=<value> -
 * http://192.168
 * .18.31:8180/search/rest/index/product/emf/merchantFactor/merchant1?val=5.0
 * 
 */
public class IndexServlet extends AbstractServlet {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	ClusterService clusterService;

	IndicesService indicesService;

	public enum Data {
		INDEXES, INEDX,

		DOCS, DOC,

		EMFS, EMF_VALUES, EMF_VALUE
	}

	public enum OperationType {
		DESC, // dump the value or description
		SET, // update the value (add if it's missing)
		UPDATEDOC
		// update doc
	}

	public static class Operation {

		Data data;
		OperationType ops;
		String indexName;
		String param;
		String param2;
		Float value;

		String state = "Ok";

		Operation() {
		}

		public Operation(Data type, OperationType ops, String indexName,
				String param, String param2) {
			this.data = type;
			this.ops = ops;
			this.indexName = indexName;
			this.param = param;
			this.param2 = param2;
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == null || !(obj instanceof Operation)) {
				return false;
			}
			Operation other = (Operation) obj;
			if (indexName == null ? other.indexName != null : !indexName
					.equals(other.indexName)) {
				return false;
			}
			if (param == null ? other.param != null : !param
					.equals(other.param)) {
				return false;
			}
			if (param2 == null ? other.param2 != null : !param2
					.equals(other.param2)) {
				return false;
			}
			return true;
		}

		@Override
		public String toString() {
			return "Operation [type=" + data + ", indexName=" + indexName
					+ ", param=" + param + ", param2=" + param2 + "]";
		}

	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {

		ClusterState cs = clusterService.state();

		String returnJson = "{'respState':'OK'}";

		Operation op = getOps(req);
		if (op.ops == OperationType.UPDATEDOC) {
			try {
				req.setAttribute("indexName", op.indexName);
				String indexDoc = req.getParameter("indexDoc");
				if (indexDoc == null) {
					RequestDispatcher rd = req.getRequestDispatcher("/jsp/"
							+ op.indexName + "/index.jsp");
					rd.forward(req, resp);
				} else {
					IndexRequest indexRequest = JsonConvertor.fromJson(
							indexDoc, IndexRequest.class);
					brokerService.execute(indexRequest);
					super.respJson(req, resp, returnJson);
				}
			} catch (Exception e) {
				returnJson = e.getMessage();
				super.respJson(req, resp, returnJson);
			}

		} else {

			Object ret = op;
			boolean wtJson = true;
			switch (op.data) {
			case INDEXES:
				ret = cs.indexMetas().indexNames();
				break;
			case INEDX:
				ret = indicesService.getSchemaXml(op.indexName);
				wtJson = false;
				break;
			case DOCS:
				// no impl
				break;
			case DOC:
				// no impl
				break;
			case EMFS:
				ret = MemDataManager.getDataProviders(op.indexName);
				break;
			case EMF_VALUES:
				ret = MemDataManager.getDataProvider(op.indexName, op.param,
						null).getAll();
				break;
			case EMF_VALUE:
				if (op.ops.equals(OperationType.DESC)) {
					ret = MemDataManager.getDataProvider(op.indexName,
							op.param, null).get(op.param2);
				} else {
					MemDataManager
							.getDataProvider(op.indexName, op.param, null).put(
									op.param2, op.value);
				}
				break;
			default:
				break;
			}

			if (wtJson) {
				String json = gson.toJson(ret);
				super.respJson(req, resp, json);
			} else {
				String xml = ret.toString();
				super.respXml(req, resp, xml);
			}
		}

	}

	private Operation getOps(HttpServletRequest req) {
		Operation op = getOps(req.getRequestURI());

		String value = req.getParameter("val");
		if (value != null) {
			Float f = Float.parseFloat(value);
			if (f != null) {
				op.ops = OperationType.SET;
				op.value = f;
			}
		}

		return op;
	}

	public static Operation getOps(String path) {
		Operation op = new Operation();
		op.data = Data.INDEXES;

		op.ops = OperationType.DESC;

		String prefix = "rest/index";
		String suffix = null;
		if (path != null) {
			int pos = path.indexOf(prefix);
			if (pos >= 0) {
				suffix = path.substring(pos + prefix.length());
			}
		}

		// "rest/index", return index names
		if (suffix == null || suffix.isEmpty()) {
			return op;
		}

		// rest/index/, return index names too.
		if (suffix.startsWith("/")) {
			suffix = suffix.substring(1);
		}
		String[] splits = suffix.split("/");
		if (splits == null || splits.length == 0 || splits[0].equals("")) {
			return op;
		}

		op.indexName = splits[0];

		if (splits.length == 1) {
			op.data = Data.INEDX;
		} else if (splits.length == 2) {
			if (splits[1].equals("docs")) {
				op.data = Data.DOCS;
			} else if (splits[1].equals("emfs")) {
				op.data = Data.EMFS;
			} else if (splits[1].equals("updateDoc")) {
				op.ops = OperationType.UPDATEDOC;
			}
		} else if (splits.length == 3) {
			if (splits[1].equals("doc")) {
				op.data = Data.DOCS;
			} else if (splits[1].equals("emf")) {
				op.data = Data.EMF_VALUES;
			}

			op.param = splits[2];
		} else if (splits.length == 4) {
			if (splits[1].equals("emf")) {
				op.data = Data.EMF_VALUE;
				op.param = splits[2];
				op.param2 = splits[3];
			}
		}

		return op;
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doGet(req, resp);
	}

	@Override
	public void init() throws ServletException {
		super.init();

		clusterService = injector.getInstance(ClusterService.class);

		indicesService = injector.getInstance(IndicesService.class);

	}

}
